/*
 * Unidata Platform Community Edition
 * Copyright (c) 2013-2020, UNIDATA LLC, All rights reserved.
 * This file is part of the Unidata Platform Community Edition software.
 *
 * Unidata Platform Community Edition is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Unidata Platform Community Edition is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
 */

package org.unidata.mdm.data.service.segments.relations.delete;

import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Objects;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.unidata.mdm.core.type.calculables.CalculableHolder;
import org.unidata.mdm.core.type.calculables.ModificationBox;
import org.unidata.mdm.core.type.data.DataRecord;
import org.unidata.mdm.core.type.data.DataShift;
import org.unidata.mdm.core.type.data.OperationType;
import org.unidata.mdm.core.type.data.RecordStatus;
import org.unidata.mdm.core.type.data.impl.SerializableDataRecord;
import org.unidata.mdm.core.util.SecurityUtils;
import org.unidata.mdm.data.context.DeleteRelationRequestContext;
import org.unidata.mdm.data.module.DataModule;
import org.unidata.mdm.data.type.calculables.impl.RelationRecordHolder;
import org.unidata.mdm.data.type.data.OriginRelation;
import org.unidata.mdm.data.type.data.OriginRelationInfoSection;
import org.unidata.mdm.data.type.data.RelationType;
import org.unidata.mdm.data.type.data.impl.OriginRelationImpl;
import org.unidata.mdm.data.type.keys.RelationKeys;
import org.unidata.mdm.data.type.timeline.RelationTimeInterval;
import org.unidata.mdm.system.service.PlatformConfiguration;
import org.unidata.mdm.system.type.pipeline.Point;
import org.unidata.mdm.system.type.pipeline.Start;
import org.unidata.mdm.system.type.runtime.MeasurementPoint;

/**
 * @author Mikhail Mikhailov
 * Prepares upsert context.
 */
@Component(RelationDeleteModboxExecutor.SEGMENT_ID)
public class RelationDeleteModboxExecutor extends Point<DeleteRelationRequestContext> {
    /**
     * This segment ID.
     */
    public static final String SEGMENT_ID = DataModule.MODULE_ID + "[RELATION_DELETE_MODBOX]";
    /**
     * Localized message code.
     */
    public static final String SEGMENT_DESCRIPTION = DataModule.MODULE_ID + ".relation.delete.modbox.description";
    /**
     * PC.
     */
    @Autowired
    private PlatformConfiguration platformConfiguration;
    /**
     * Constructor.
     */
    public RelationDeleteModboxExecutor() {
        super(SEGMENT_ID, SEGMENT_DESCRIPTION);
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public void point(DeleteRelationRequestContext ctx) {

        // 1. Containments are processed by record services entirely
        if (ctx.relationType() == RelationType.CONTAINS) {
            return;
        }

        MeasurementPoint.start();
        try {

            Collection<CalculableHolder<OriginRelation>> input = Collections.emptyList();

            // 2. Process user data. If the boundaries should be checked and possibly fixed, this must be done prior to this segment.
            DataRecord data = ctx.getRecord();
            if (Objects.nonNull(data)) {

                RelationKeys relationKeys = ctx.relationKeys();
                OperationType operationType = ctx.operationType();
                Date ts = ctx.timestamp();
                String user = SecurityUtils.getCurrentUserName();

                // 3. Push upsert
                OriginRelationInfoSection oris = new OriginRelationInfoSection()
                            .withRelationName(relationKeys.getRelationName())
                            .withRelationType(relationKeys.getRelationType())
                            .withRelationOriginKey(relationKeys.getOriginKey())
                            .withValidFrom(ctx.getValidFrom())
                            .withValidTo(ctx.getValidTo())
                            .withFromEntityName(relationKeys.getFromEntityName())
                            .withToEntityName(relationKeys.getToEntityName())
                            .withStatus(ctx.isInactivatePeriod() ? RecordStatus.INACTIVE : RecordStatus.ACTIVE)
                            .withShift(DataShift.PRISTINE)
                            .withOperationType(operationType == null ? OperationType.DIRECT : operationType)
                            .withMajor(platformConfiguration.getPlatformMajor())
                            .withMinor(platformConfiguration.getPlatformMinor())
                            .withCreateDate(ts)
                            .withUpdateDate(ts)
                            .withCreatedBy(user)
                            .withUpdatedBy(user);

                OriginRelation origin = new OriginRelationImpl()
                            .withDataRecord(data)
                            .withInfoSection(oris);

                input = Collections.singleton(new RelationRecordHolder(origin));
            }

            ModificationBox<OriginRelation> box = new RelationTimeInterval(ctx.getValidFrom(), ctx.getValidTo(), input);
            box.setCalculationState(SerializableDataRecord.of(data));

            ctx.modificationBox(box);
        } finally {
            MeasurementPoint.stop();
        }
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public boolean supports(Start<?, ?> start) {
        return DeleteRelationRequestContext.class.isAssignableFrom(start.getInputTypeClass());
    }
}
